home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / fish / 001-100 / 001-025 / 005 / input.dev / input.dev.c < prev    next >
C/C++ Source or Header  |  1995-03-17  |  10KB  |  287 lines

  1. /*
  2.  *
  3.  *    DISCLAIMER:
  4.  *
  5.  *    This program is provided as a service to the programmer
  6.  *    community to demonstrate one or more features of the Amiga
  7.  *    personal computer.  These code samples may be freely used
  8.  *    for commercial or noncommercial purposes.
  9.  * 
  10.  *     Commodore Electronics, Ltd ("Commodore") makes no
  11.  *    warranties, either expressed or implied, with respect
  12.  *    to the program described herein, its quality, performance,
  13.  *    merchantability, or fitness for any particular purpose.
  14.  *    This program is provided "as is" and the entire risk
  15.  *    as to its quality and performance is with the user.
  16.  *    Should the program prove defective following its
  17.  *    purchase, the user (and not the creator of the program,
  18.  *    Commodore, their distributors or their retailers)
  19.  *    assumes the entire cost of all necessary damages.  In 
  20.  *    no event will Commodore be liable for direct, indirect,
  21.  *    incidental or consequential damages resulting from any
  22.  *    defect in the program even if it has been advised of the 
  23.  *    possibility of such damages.  Some laws do not allow
  24.  *    the exclusion or limitation of implied warranties or
  25.  *    liabilities for incidental or consequential damages,
  26.  *    so the above limitation or exclusion may not apply.
  27.  *
  28.  */
  29.  
  30. /* sample program for adding an input handler to the input stream */
  31.  
  32. /* note that this program also uses the PrepareTimer and SetTimer
  33.  * and DeleteTimer described in the timer device chapter.  (PrepareTimer
  34.  * is also sometimes called CreateTimer).  Must be linked with 
  35.  * handler.interface.asm (object) in order to run.
  36.  *
  37.  */
  38.  
  39. /* note also that compiling this program native on the Amiga requires
  40.  * a separate compile for this program, a separate assembly for the
  41.  * handler.interface.asm, and a separate alink phase.  Alink will
  42.  * be used to tie together the object files produced by the separate
  43.  * language phases.
  44.  *
  45.  * Author:  Rob Peck, 12/1/85
  46.  */
  47.  
  48. #include <exec/types.h>
  49. #include <exec/ports.h>
  50. #include <exec/memory.h>
  51. #include <exec/io.h>
  52. #include <exec/tasks.h>
  53. #include <exec/interrupts.h>
  54. #include <devices/input.h>
  55. #include <exec/devices.h>
  56. #include <devices/inputevent.h>
  57.  
  58. #define F1KEYUP 0xD0
  59. struct InputEvent copyevent;    /* local copy of the event */
  60.                 /* assumes never has a next.event attached */
  61. struct MsgPort *inputDevPort;
  62. struct IOStdReq *inputRequestBlock;
  63. struct Interrupt handlerStuff;
  64.  
  65. struct InputEvent dummyEvent;
  66.  
  67. extern struct MsgPort *CreatePort();
  68. extern struct IOStdReq *CreateStdIO();
  69.  
  70. struct MemEntry me[10];
  71.  
  72.     /* If we want the input handler itself to add anything to the
  73.      * input stream, we will have to keep track of any dynamically
  74.      * allocated memory so that we can later return it to the system.
  75.      * Other handlers can break any internal links the handler puts
  76.      * in before it passes the input events.
  77.      */
  78.  
  79. struct InputEvent 
  80. *myhandler(ev, mydata)
  81.     struct InputEvent *ev;     /* and a pointer to a list of events */
  82.     struct MemEntry *mydata[];  /* system will pass me a pointer to my 
  83.                      * own data space.
  84.                  */
  85. {
  86.     /* demo version of program simply reports input events as
  87.      * its sees them; passes them on unchanged.  Also, if there
  88.      * is a linked chain of input events, reports only the lead
  89.      * one in the chain, for simplicity.  
  90.      */
  91.     if(ev->ie_Class == IECLASS_TIMER) 
  92.     {
  93.         return(ev);
  94.     }
  95.     /* don't try to print timer events!!! they come every 1/10th sec. */
  96.      else 
  97.     {
  98.         Forbid();  /* don't allow a mix of events to be reported */
  99.                copyevent.ie_Class = ev->ie_Class;
  100.             copyevent.ie_SubClass = ev->ie_SubClass;
  101.             copyevent.ie_Code =  ev->ie_Code;
  102.             copyevent.ie_Qualifier = ev->ie_Qualifier;
  103.             copyevent.ie_X = ev->ie_X;
  104.             copyevent.ie_Y = ev->ie_Y;
  105.             copyevent.ie_TimeStamp.tv_secs = ev->ie_TimeStamp.tv_secs;
  106.             copyevent.ie_TimeStamp.tv_micro = ev->ie_TimeStamp.tv_micro;
  107.         Permit();
  108.     }
  109.  
  110.     /* There will be lots and lots of events coming through here;
  111.      * rather than make the system slow down because something
  112.      * is busy printing the previous event, lets just print what
  113.      * we find is current, and if we miss a few, so be it.
  114.      *
  115.      * Normally this loop would "handle" the event or perhaps
  116.      * add a new one to the stream.  (At this level, the only
  117.      * events you should really be adding are mouse, rawkey or timer,
  118.      * because you are ahead of the intuition interpreter.)
  119.      * No printing is done in this loop (lets main() do it) because
  120.      * printf can't be done by anything less than a 'process'
  121.      */
  122.     return(ev);    
  123.     /* pass on the pointer to the event (most handlers would
  124.      * pass on a pointer to a changed or an unchanged stream)
  125.      * (we are simply reporting what is seen, not trying to
  126.      * modify it in any way) */
  127. }
  128.  
  129.  
  130.  
  131. /* NOTICE:  THIS PROGRAM LINKS ITSELF INTO THE INPUT STREAM AHEAD OF 
  132.  * INTUITION.  THEREFORE THE ONLY INPUT EVENTS THAT IT WILL SEE AT 
  133.  * ALL ARE TIMER, KEYBOARD and GAMEPORT.  AS NOTED IN THE PROGRAM,
  134.  * THE TIMER EVENTS ARE IGNORED DELIBERATELY */
  135.  
  136.  
  137. extern struct Task *FindTask();
  138. struct Task *mytask;
  139. LONG mysignal;
  140. extern HandlerInterface();
  141.  
  142. struct timerequest *mytimerRequest;
  143.  
  144. extern struct timerequest *PrepareTimer();
  145. extern int WaitTimer();
  146. extern int DeleteTimer();
  147.  
  148. main()
  149. {
  150.     SHORT error;
  151.     ULONG oldseconds, oldmicro, oldclass;
  152.  
  153.     /* init dummy event, this is what we will feed to other handlers
  154.      * while this handler is active */
  155.     
  156.     dummyEvent.ie_Class = IECLASS_NULL; /* no event happened */
  157.     dummyEvent.ie_NextEvent = NULL;    /* only this one in the chain */
  158.     
  159.     inputDevPort = CreatePort(0,0);        /* for input device */
  160.     if(inputDevPort == NULL) exit(-1);    /* error during createport */
  161.     inputRequestBlock = CreateStdIO(inputDevPort);     
  162.     if(inputRequestBlock == 0) { DeletePort(inputDevPort); exit(-2); }
  163.                     /* error during createstdio */
  164.  
  165.     mytimerRequest = PrepareTimer();
  166.     if(mytimerRequest == NULL) exit(-3);
  167.  
  168.     handlerStuff.is_Data = (APTR)&me[0];
  169.             /* address of its data area */
  170.     handlerStuff.is_Code = (VOID)HandlerInterface;
  171.             /* address of entry point to handler */
  172.     handlerStuff.is_Node.ln_Pri = 51;
  173.             /* set the priority one step higher than
  174.               * Intution, so that our handler enters
  175.              * the chain ahead of Intuition.
  176.              */
  177.     error = OpenDevice("input.device",0,inputRequestBlock,0);
  178.     if(error == 0) printf("\nOpened the input device");
  179.  
  180.     inputRequestBlock->io_Command = IND_ADDHANDLER;
  181.     inputRequestBlock->io_Data = (APTR)&handlerStuff;
  182.         
  183.     DoIO(inputRequestBlock);
  184.     copyevent.ie_TimeStamp.tv_secs = 0;
  185.     copyevent.ie_TimeStamp.tv_micro = 0;
  186.     copyevent.ie_Class = 0;
  187.     oldseconds = 0;
  188.     oldmicro = 0;
  189.     oldclass =0;
  190.  
  191.     for(;;)            /* FOREVER */
  192.     {
  193.     WaitForTimer(mytimerRequest, 0, 100000);    
  194.             /* TRUE = wait; time = 1/10th second */
  195.  
  196.     /* note: while this task is asleep, it is very very likely that
  197.      * one or more events will indeed pass through the input handler.
  198.      * This task will only print a few of them, but won't intermix
  199.      * the pieces of the input event itself because of the Forbid()
  200.      * and Permit() (not allow task swapping when a data structure
  201.      * isn't internally consistent) 
  202.      */
  203.     if(copyevent.ie_Class == IECLASS_RAWKEY && copyevent.ie_Code == F1KEYUP)
  204.         break;                /* exit from forever */
  205.     else
  206.        {
  207.         Forbid();
  208.         if(copyevent.ie_TimeStamp.tv_secs != oldseconds ||
  209.             copyevent.ie_TimeStamp.tv_micro != oldmicro ||
  210.             copyevent.ie_Class != oldclass )
  211.         {
  212.             oldseconds = copyevent.ie_TimeStamp.tv_secs;    
  213.             oldmicro   = copyevent.ie_TimeStamp.tv_micro;    
  214.             oldclass   = copyevent.ie_Class;
  215.             showEvents(©event);
  216.         }
  217.         Permit();
  218.        }
  219.     }
  220.     /* Although this task sleeps (main loop), the handler is independently
  221.      * called by the input device.
  222.      */
  223.  
  224.     /* For keystrokes that might be recognized by AmigaDOS, such as
  225.       * alphabetic or numeric keys, you will notice that after the
  226.      * first such keystroke, AmigaDOS appears to lock out your task
  227.      * and accepts all legal keystrokes until you finally hit return.
  228.      * This is absolutely true.... when both you and AmigaDOS try to
  229.      * write into the same window, as is true if you run this program
  230.      * from the CLI, the first keystroke recognized by AmigaDOS locks
  231.      * the layer into which it is writing.  Any other task trying
  232.      * to write into this same layer is put to sleep.  This allows
  233.      * AmigaDOS to edit the input line and prevents other output to
  234.      * that same window from upsetting the input line appearance.
  235.      * In the same manner, while your task is sending a line of output,
  236.      * AmigaDOS can be put to sleep it too must output at that time.
  237.      *
  238.      * You can avoid this problem if you wish by opening up a separate
  239.      * window and a console device attached to that window, and output
  240.      * strings to that console.  If you click the selection button on
  241.      * this new window, then AmigaDOS won't see the input and your
  242.      * task will get to see all of the keystrokes.  The other alternative
  243.      * you can use, for demonstration sake, is to:
  244.      *
  245.      *    1.  Make the AmigaDOS window slightly smaller in the 
  246.      *         vertical direction.  
  247.      *    2.  Then click in the Workbench screen area outside 
  248.      *        of any window. 
  249.      * 
  250.      * Now there is no console device (particularly not AmigaDOS's
  251.      * console) receiving the raw key stream and your task will report
  252.      * as many keystrokes as it can catch (while not sleeping, that
  253.      * is).
  254.      */
  255.     
  256.     /* remove the handler from the chain */
  257.     inputRequestBlock->io_Command = IND_REMHANDLER;
  258.     inputRequestBlock->io_Data = (APTR)&handlerStuff;
  259.     DoIO(inputRequestBlock);
  260.  
  261.     /* close the input device */
  262.     CloseDevice(inputRequestBlock);
  263.  
  264.     /* delete the IO request */
  265.     DeleteStdIO(inputRequestBlock);
  266.  
  267.     /* free other system stuff */
  268.     DeletePort(inputDevPort);
  269.     DeleteTimer(mytimerRequest);
  270. }                    /* end of main */
  271.  
  272. int
  273. showEvents(e)
  274. struct InputEvent *e;
  275. {
  276.     printf("\n\nNew Input Event");
  277.         printf("\nie_Class = %lx",e->ie_Class);
  278.         printf("\nie_SubClass = %lx",e->ie_SubClass);
  279.         printf("\nie_Code = %lx", e->ie_Code);
  280.         printf("\nie_Qualifier = %lx",e->ie_Qualifier);
  281.         printf("\nie_X = %ld", e->ie_X);
  282.         printf("\nie_Y = %ld", e->ie_Y);
  283.         printf("\nie_TimeStamp(seconds) = %lx", e->ie_TimeStamp.tv_secs);
  284.         return(0);
  285. }
  286.  
  287.